package com.allwees.bs.module.mms.service.impl;

import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.allwees.bs.core.modelbase.exception.BusinessException;
import com.allwees.bs.module.base.service.impl.BoServiceImpl;
import com.allwees.bs.module.mms.dao.RetailerApplyDao;
import com.allwees.bs.module.mms.encrypt.ApplyEmailEncryptor;
import com.allwees.bs.module.mms.entity.RetailerApply;
import com.allwees.bs.module.mms.req.RetailerApplyAuditReq;
import com.allwees.bs.module.mms.req.register.RetailerRegisterAccountReq;
import com.allwees.bs.module.mms.req.register.RetailerRegisterBaseReq;
import com.allwees.bs.module.mms.req.register.RetailerRegisterResendNewEmailReq;
import com.allwees.bs.module.mms.req.register.RetailerRegisterResendReq;
import com.allwees.bs.module.mms.req.register.RetailerRegisterVerifyReq;
import com.allwees.bs.module.mms.service.RetailerApplyService;
import com.allwees.bs.module.mms.wf.ERetailerApplyAction;
import com.allwees.bs.module.mms.wf.ERetailerApplyState;
import com.allwees.core.common.constant.EStatus;
import com.allwees.core.common.util.freemarker.FreeMarkerUtil;
import com.allwees.sender.EMailSender;
import com.allwees.sender.sms.SmsSender;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;

/**
 * @author yangylsky
 * @since 2019-12-03
 */
@Service
public class RetailerApplyServiceImpl extends BoServiceImpl<RetailerApplyDao, RetailerApply> implements RetailerApplyService {

    @Value("${rsa.private_key}")
    private String privateKey;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private EMailSender mailSender;
    @Autowired
    private SmsSender smsSender;
    @Autowired
    protected FreeMarkerUtil freeMarkerUtil;

    @Override
    @Transactional
    public RetailerApply registerVerify(RetailerRegisterVerifyReq req) {
        Integer existedCount = baseMapper.selectCountByEmailWithRejected(req.getEmail());
        if (existedCount > 0) {
            throw new BusinessException("当前用户已注册，请直接登录后操作");
        }

        RSA rsa = new RSA(privateKey, null);

        RetailerApply retailerApply = req.toEntity();
        retailerApply.setEStatus(EStatus.MMS_PERFECT_INFO);

        retailerApply.setPassword(passwordEncoder.encode(new String(rsa.decrypt(req.getPassword(), KeyType.PrivateKey))));
        save(retailerApply);

        _sendVerifyEmail(retailerApply.getUuid(), retailerApply.getFirstName(), req.getEmail());

        return findByUuid(retailerApply.getUuid());
    }

    @Override
    @Transactional
    public void registerResend(RetailerRegisterResendNewEmailReq req) {
        Integer existedCount = baseMapper.selectCountByEmailWithRejected(req.getEmail());
        if (existedCount > 0) {
            throw new BusinessException("当前用户已注册");
        }

        RetailerApply retailerApply = checkByUuid(req.getUuid());

        RetailerApply update = new RetailerApply();
        update.setUuid(req.getUuid());
        update.setEmail(req.getEmail());
        updateByUuid(update);

        _sendVerifyEmail(req.getUuid(), retailerApply.getFirstName(), req.getEmail());
    }

    @Override
    public void registerResend(RetailerRegisterResendReq req) {
        RetailerApply retailerApply = checkByUuid(req.getUuid());
        _sendVerifyEmail(retailerApply.getUuid(), retailerApply.getFirstName(), retailerApply.getEmail());
    }

    @Override
    public void registerEmailVerify(String uuid) {
        checkByUuid(uuid);

        RetailerApply applyUpdate = new RetailerApply();
        applyUpdate.setUuid(uuid);
        applyUpdate.setEmailVerified(1);
        updateByUuid(applyUpdate);
    }

    @Override
    @Transactional
    public RetailerApply registerBase(RetailerRegisterBaseReq req) {
        Integer existedCount = baseMapper.selectCountByStoreNameWithApproved(req.getStoreName());
        if (existedCount > 0) {
            throw new BusinessException("当前店铺已注册");
        }
        RetailerApply retailerApply = checkByUuid(req.getUuid());
        if (!retailerApply.emailVerified()) {
            throw new BusinessException("邮箱未验证");
        }
        updateByUuid(req.toEntity());
        return findByUuid(req.getUuid());
    }

    @Override
    @Transactional
    public RetailerApply registerAccount(RetailerRegisterAccountReq req) {
        Integer existedCount = baseMapper.selectCountByCompanyNameWithRejected(req.getCompanyName());
        if (existedCount > 0) {
            throw new BusinessException("当前企业已注册");
        }

        RetailerApply retailerApply = req.toEntity();
        retailerApply.start(ERetailerApplyState.START, ERetailerApplyAction.RETAILER_COMMIT);
        updateByUuid(retailerApply);
        return findByUuid(req.getUuid());
    }

    @Override
    public boolean registerIsEmailVerified(String uuid) {
        RetailerApply retailerApply = checkByUuid(uuid);
        return retailerApply.emailVerified();
    }

    @Override
    @Transactional
    public void audit(RetailerApplyAuditReq req) {
        for (String uuid : req.getRetailerApplyUuids()) {
            RetailerApply retailerApply = findByUuid(uuid);

            if (StringUtils.isBlank(retailerApply.getFirstAuditUserUuid())) {
                retailerApply.setFirstAuditUserUuid(req.getBranchUserUuid());
            } else if (StringUtils.isBlank(retailerApply.getFinalAuditUserUuid())) {
                retailerApply.setFinalAuditUserUuid(req.getBranchUserUuid());
            }
            retailerApply.setReason(req.getReason());
            //根据当前申请状态获取审批action
            EStatus status = EStatus.byValue(retailerApply.getStatus());
            ERetailerApplyAction action = getAuditAction(status, req.isApproved());
            retailerApply.signal(action, req.getReason(), req.getRemark(), req.getPhotos());
            updateByUuid(retailerApply);

            if (action.isFinal()) {
                sendEmailMessage(req.isApproved(),retailerApply);
            }
        }
    }

    @Override
    public String findAuditStatus(String phone) {
        RetailerApply retailerApply = baseMapper.selectByPhone(phone);
        return retailerApply == null ? "手机号不存在" : ERetailerApplyState.valueOf(retailerApply.getState()).desc();
    }

    private ERetailerApplyAction getAuditAction(EStatus status, boolean approved) {
        switch (status) {
            case WAIT_AUDIT:
                return approved ? ERetailerApplyAction.PLATFORM_FIRST_APPROVED : ERetailerApplyAction.PLATFORM_FIRST_REJECTED;
            case MMS_FIRST_AUDIT_APPROVED:
                return approved ? ERetailerApplyAction.PLATFORM_FINAL_APPROVED : ERetailerApplyAction.PLATFORM_FINAL_REJECTED;
            default:
                throw new BusinessException("当前用户处于非审批状态~");
        }
    }

    private void _sendVerifyEmail(String uuid, String name, String email) {
        Map<String, String> params = new HashMap<>(2);
        params.put("uuid", ApplyEmailEncryptor.encrypt(uuid));
        params.put("name", name != null ? name : "");

        String content = freeMarkerUtil.render("resister_verify_email.ftl", params);
        mailSender.send(email, "欢迎注册Allwees商户平台！", content, true);
    }

    private void sendEmailMessage(boolean approved, RetailerApply retailerApply) {
        Map<String, Object> params = new HashMap<>(3);
        params.put("uuid", ApplyEmailEncryptor.encrypt(retailerApply.getUuid()));
        params.put("name", StringUtils.trimToEmpty(retailerApply.getLastName() + retailerApply.getFirstName()));
        params.put("reason", retailerApply.getReason());

        String templateUrl = approved ? "resister_audit_approved.ftl" : "resister_audit_reject.ftl";
        String content = freeMarkerUtil.render(templateUrl, params);

        String subject = approved ? "欢迎进入Allwees商户平台" : "审核失败";
        mailSender.send(retailerApply.getEmail(), subject, content, true);
    }
}

